package pub.dsb.admin.config;


import org.flowable.ui.common.conf.DevelopmentConfiguration;
import org.flowable.ui.common.rest.idm.remote.RemoteAccountResource;
import org.flowable.ui.modeler.conf.ApplicationConfiguration;
import org.flowable.ui.modeler.conf.SecurityConfiguration;
import org.flowable.ui.modeler.properties.FlowableModelerAppProperties;
import org.flowable.ui.modeler.security.RemoteIdmAuthenticationProvider;
import org.flowable.ui.modeler.servlet.ApiDispatcherServletConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;


import java.io.IOException;
import java.util.Arrays;
import java.util.List;


/**
 * <p>
 * 工作流审核权限配置
 * </p>
 *
 * @author Yiyuery
 * @date 2020/8/13 12:06
 * @since 1.1.0
 */
@Configuration
@EnableWebSecurity
public class FlowableConfiguration extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().permitAll()
                .and().logout().permitAll()
                .and().csrf().disable();
    }


    @Bean
    public ServletRegistrationBean appServlet(ApplicationContext applicationContext) {
        AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();
        dispatcherServletConfiguration.setParent(applicationContext);
        dispatcherServletConfiguration.register(AppConfiguration.class);
        DispatcherServlet servlet = new DispatcherServlet(dispatcherServletConfiguration);
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet, new String[]{"/*"});
        registrationBean.setName("Flowable Modeler App Prefix Servlet");
        registrationBean.setLoadOnStartup(2);
        registrationBean.setAsyncSupported(true);
        return registrationBean;
    }


    @Bean
    public ServletRegistrationBean modelerApiServlet(ApplicationContext applicationContext) {
        AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();
        dispatcherServletConfiguration.setParent(applicationContext);
        dispatcherServletConfiguration.register(new Class[]{ApiDispatcherServletConfiguration.class});
        DispatcherServlet servlet = new DispatcherServlet(dispatcherServletConfiguration);
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet, new String[]{"/api/*"});
        registrationBean.setName("Flowable Modeler App API Servlet");
        registrationBean.setLoadOnStartup(1);
        registrationBean.setAsyncSupported(true);
        return registrationBean;
    }

    @ComponentScan(basePackages = {
            "org.flowable.ui.modeler.conf",
            "org.flowable.ui.modeler.repository",
            "org.flowable.ui.modeler.service",
            "org.flowable.ui.modeler.rest.app",
            "org.flowable.ui.common.repository",
            "org.flowable.ui.common.service",
            "org.flowable.ui.common.tenant"
    }, excludeFilters = {
            @ComponentScan.Filter(type = FilterType.CUSTOM, classes = FlowableConfiguration.ExcludeFilter.class)
    })
    @EnableConfigurationProperties({FlowableModelerAppProperties.class})
    static class AppConfiguration {
    }


    /**
     * <p>
     * 忽略配置类
     * </p>
     *
     * @author Yiyuery
     * @date 2020/8/13 13:50
     * @since 1.0
     */
    static class ExcludeFilter implements TypeFilter {


        /**
         * 剔除部分鉴权代码
         */
        private static List<String> excludes = Arrays.asList(ApiDispatcherServletConfiguration.class.getName(),
                ApplicationConfiguration.class.getName(),
                RemoteAccountResource.class.getName(),
                SecurityConfiguration.class.getName(),
                RemoteIdmAuthenticationProvider.class.getName(),
                SecurityConfiguration.ActuatorWebSecurityConfigurationAdapter.class.getName(),
                SecurityConfiguration.ApiWebSecurityConfigurationAdapter.class.getName(),
                SecurityConfiguration.FormLoginWebSecurityConfigurerAdapter.class.getName(),
                DevelopmentConfiguration.class.getName());


        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
                throws IOException {
            return excludes.contains(metadataReader.getClassMetadata().getClassName());
        }


        @Override
        public boolean equals(Object obj) {
            throw new IllegalStateException("ExcludeFilter " + getClass() + " has not implemented equals");
        }


        @Override
        public int hashCode() {
            throw new IllegalStateException("ExcludeFilter " + getClass() + " has not implemented hashCode");
        }
    }

}